Skip to content

Vue Router 中 History 与 Hash 模式深入对比

一、核心要点速览

💡 核心考点

  • Hash 模式: URL 带 #,兼容性好,无需后端配置
  • History 模式: URL 美观,需要后端支持,HTML5 History API
  • 关键差异: URL 形式、刷新行为、SEO、部署配置
  • 生产环境: 推荐 History 模式 + Nginx 配置

二、基础概念

1. Hash 模式

javascript
// Hash 模式的 URL 示例
https://example.com/#/home
https://example.com/#/user/123
https://example.com/#/search?q=vue

// 特点:
// ✓ # 后面的内容不会发送到服务器
// ✓ 改变 hash 不会刷新页面
// ✓ 通过 hashchange 事件监听变化

window.addEventListener('hashchange', () => {
  console.log('Hash 变化:', window.location.hash)
})

// Vue Router 配置
const router = new VueRouter({
  mode: 'hash',
  routes: [...]
})

2. History 模式

javascript
// History 模式的 URL 示例
https://example.com/home
https://example.com/user/123
https://example.com/search?q=vue

// 特点:
// ✓ URL 美观,符合常规网站结构
// ✓ 使用 HTML5 History API (pushState, replaceState)
// ✓ 需要后端配置支持

window.addEventListener('popstate', () => {
  console.log('History 状态变化:', window.location.pathname)
})

// Vue Router 配置
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

三、工作原理对比

1. Hash 模式原理

┌──────────────────────────────────────────────────────────┐
│              Hash 模式工作原理                            │
└──────────────────────────────────────────────────────────┘

工作流程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 用户访问:https://example.com/#/home

2. 浏览器请求服务器:
   ┌────────────────────────────┐
   │ GET /                      │
   │ Host: example.com          │
   │                            │
   │ ❌ #/home 不会发送给服务器  │
   └────────────────────────────┘

3. 服务器返回 index.html

4. 前端 JavaScript 执行:
   ┌────────────────────────────┐
   │ 读取 location.hash         │
   │ → "#/home"                 │
   │                            │
   │ 匹配路由规则               │
   │ 渲染对应组件               │
   └────────────────────────────┘

5. 监听 hash 变化:
   ┌────────────────────────────┐
   │ window.onhashchange = () =>│
   │   updateView()             │
   └────────────────────────────┘

关键技术点:
  ✓ location.hash 获取 hash 值
  ✓ hashchange 事件监听
  ✓ 不触发页面刷新
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

2. History 模式原理

┌──────────────────────────────────────────────────────────┐
│           History 模式工作原理                            │
└──────────────────────────────────────────────────────────┘

工作流程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 用户访问:https://example.com/home

2. 浏览器请求服务器:
   ┌────────────────────────────┐
   │ GET /home                  │
   │ Host: example.com          │
   │                            │
   │ ✓ 完整路径发送给服务器     │
   └────────────────────────────┘

3. 服务器需要返回 index.html:
   ┌────────────────────────────┐
   │ 如果没有配置:             │
   │ ❌ 404 Not Found           │
   │                            │
   │ 如果正确配置:             │
   │ ✓ 返回 index.html          │
   └────────────────────────────┘

4. 前端 JavaScript 执行:
   ┌────────────────────────────┐
   │ 读取 location.pathname     │
   │ → "/home"                  │
   │                            │
   │ 匹配路由规则               │
   │ 渲染对应组件               │
   └────────────────────────────┘

5. 使用 History API 导航:
   ┌────────────────────────────┐
   │ history.pushState(         │
   │   state,                   │
   │   title,                   │
   │   '/about'                 │
   │ )                          │
   │                            │
   │ popstate 事件监听          │
   └────────────────────────────┘

关键技术点:
  ✓ history.pushState() 添加历史记录
  ✓ history.replaceState() 修改当前记录
  ✓ popstate 事件监听
  ✓ 刷新会发送请求到服务器
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

3. 时序图对比

时间 →  ─────────────────────────────────────────────────►

Hash 模式导航流程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
用户点击链接


location.hash = '#/about'

  ├─────► 浏览器
  │       │
  │       │ 不发送请求
  │       ▼
  │     触发 hashchange 事件
  │       │
  │       ▼
  │     Vue Router 拦截
  │       │
  │       ▼
  │     匹配路由
  │       │
  │       ▼
  │     渲染组件
  │       │
  │       ▼
  └───► 视图更新

✓ 无需服务器参与
✓ 不会刷新页面
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

History 模式导航流程:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
用户点击链接


history.pushState('/about')

  ├─────► 浏览器
  │       │
  │       │ 不发送请求(同域)
  │       ▼
  │     触发 popstate 事件
  │       │
  │       ▼
  │     Vue Router 拦截
  │       │
  │       ▼
  │     匹配路由
  │       │
  │       ▼
  │     渲染组件
  │       │
  │       ▼
  │     视图更新

  └─► 但如果刷新页面:


      浏览器发送 GET /about


      服务器需要返回 index.html


      前端重新初始化路由

⚠️ 刷新需要服务器配置
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

四、详细对比表

特性Hash 模式History 模式
URL 形式#/home/home
美观度⭐⭐⭐⭐⭐⭐⭐
SEO 友好⭐⭐⭐⭐⭐⭐⭐
兼容性IE8+IE10+
服务器配置不需要需要
刷新行为正常需配置否则 404
实现方式hashchange 事件HTML5 History API
安全性较低(hash 暴露)较高
带宽占用略多(hash 也传输)正常
开发便利简单需配置服务器

五、优缺点分析

1. Hash 模式

┌──────────────────────────────────────────────────────────┐
│                Hash 模式优缺点                            │
└──────────────────────────────────────────────────────────┘

优点 ✓:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌────────────────────────────────┐
│ ✓ 兼容性好                     │
│   支持 IE8 及以上               │
│   所有浏览器都支持              │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✓ 无需后端配置                 │
│   直接部署到任意静态服务器     │
│   开箱即用                     │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✓ 实现简单                     │
│   基于 hashchange 事件          │
│   技术成熟稳定                 │
└────────────────────────────────┘

缺点 ✗:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌────────────────────────────────┐
│ ✗ URL 不美观                   │
│   带有 # 符号                  │
│   不符合传统 URL 规范           │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✗ SEO 较差                     │
│   搜索引擎可能不索引 hash 内容  │
│   (虽然 Google 已改进)        │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✗ 安全性较低                   │
│   hash 信息在前端暴露          │
│   不适合敏感参数               │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✗ 额外带宽开销                 │
│   hash 也会随请求发送到服务器  │
│   (虽然服务器不处理)         │
└────────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

2. History 模式

┌──────────────────────────────────────────────────────────┐
│             History 模式优缺点                            │
└──────────────────────────────────────────────────────────┘

优点 ✓:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌────────────────────────────────┐
│ ✓ URL 美观规范                 │
│   和传统网站 URL 一致           │
│   用户体验更好                  │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✓ SEO 友好                     │
│   搜索引擎友好                  │
│   有利于页面收录                │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✓ 安全性更高                   │
│   完整的 URL 控制               │
│   可隐藏敏感参数                │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✓ 无额外开销                   │
│   不会发送额外的 hash 信息      │
└────────────────────────────────┘

缺点 ✗:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌────────────────────────────────┐
│ ✗ 需要后端配置                 │
│   需要服务器支持                │
│   部署稍复杂                    │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✗ 兼容性稍差                   │
│   仅支持 IE10+                 │
│   老浏览器需要降级              │
└────────────────────────────────┘

┌────────────────────────────────┐
│ ✗ 刷新问题                     │
│   配置不当会导致 404            │
│   需要额外注意                  │
└────────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

六、实际应用场景

1. 选择指南

项目需求分析:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
需要 SEO 优化?

    ├─ 是 → 选择 History 模式 ✓
    │   └─ 例:官网、博客、电商

    └─ 否 → 内部管理系统?

        ├─ 是 → 选择 Hash 模式 ✓
        │   └─ 例:后台、Dashboard、工具

        └─ 否 → 需要兼容老浏览器?

            ├─ 是 → 选择 Hash 模式 ✓
            │   └─ 例:政府项目、传统企业

            └─ 否 → 选择 History 模式 ✓
                └─ 例:现代 Web 应用
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

2. 推荐场景

┌──────────────────────────────────────────────────────────┐
│                   实际应用场景                           │
└──────────────────────────────────────────────────────────┘

适合 Hash 模式的场景:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ 后台管理系统
  ┌──────────────────────────────┐
  │ 不需要 SEO                   │
  │ 内网使用                     │
  │ 快速部署                     │
  │                              │
  │ 推荐:Hash 模式              │
  └──────────────────────────────┘

✓ 工具类应用
  ┌──────────────────────────────┐
  │ 在线编辑器、计算器等         │
  │ 状态保存在 URL 中            │
  │ 方便分享                     │
  │                              │
  │ 推荐:Hash 模式              │
  └──────────────────────────────┘

✓ 需要兼容 IE8-9
  ┌──────────────────────────────┐
  │ 政府、银行、传统企业项目     │
  │ 必须支持老浏览器             │
  │                              │
  │ 推荐:Hash 模式              │
  └──────────────────────────────┘

适合 History 模式的场景:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✓ 对外官网
  ┌──────────────────────────────┐
  │ 需要 SEO 优化                │
  │ URL 美观专业                 │
  │ 提升用户体验                 │
  │                              │
  │ 推荐:History 模式           │
  └──────────────────────────────┘

✓ 电商平台
  ┌──────────────────────────────┐
  │ 商品详情页需要被搜索         │
  │ 分享链接更友好               │
  │ 利于推广                     │
  │                              │
  │ 推荐:History 模式           │
  └──────────────────────────────┘

✓ 博客/内容站点
  ┌──────────────────────────────┐
  │ 文章 URL 需要美观             │
  │ 搜索引擎优化                 │
  │ 社交媒体分享                 │
  │                              │
  │ 推荐:History 模式           │
  └──────────────────────────────┘
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

七、部署配置详解

1. Nginx 配置(推荐)

nginx
# History 模式的 Nginx 配置
server {
    listen 80;
    server_name example.com;
    root /var/www/my-app;
    index index.html;

    location / {
        # 核心配置:所有路径都返回 index.html
        try_files $uri $uri/ /index.html;
        
        # 可选:添加缓存策略
        expires 1d;
        add_header Cache-Control "public, immutable";
    }

    # 静态资源优化
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}

# 如果应用有子路径,例如:example.com/my-app/
location /my-app/ {
    alias /var/www/my-app/;
    index index.html;
    
    # 重写路径,去掉 /my-app 前缀
    rewrite ^/my-app/(.*) /$1 break;
    
    # 尝试文件,不存在则返回 index.html
    try_files $uri $uri/ /my-app/index.html;
}

2. Apache 配置

apache
# .htaccess 文件配置
<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteBase /
  
  # 如果请求的是真实存在的文件或目录,直接返回
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  
  # 否则重定向到 index.html
  RewriteRule . /index.html [L]
</IfModule>

# 启用 gzip 压缩(可选)
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE application/javascript
</IfModule>

3. Node.js (Express) 配置

javascript
const express = require('express')
const path = require('path')
const app = express()

// 静态文件服务
app.use(express.static(path.join(__dirname, 'dist')))

// History 模式支持:所有路由都返回 index.html
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist/index.html'))
})

// 启动服务器
app.listen(3000, () => {
  console.log('Server running on http://localhost:3000')
})

4. Koa 配置

javascript
const Koa = require('koa')
const static = require('koa-static')
const path = require('path')
const app = new Koa()

// 静态文件服务
app.use(static(path.join(__dirname, 'dist')))

// History 模式支持
app.use(async (ctx, next) => {
  if (!ctx.url.includes('.') && ctx.status === 404) {
    ctx.type = 'text/html'
    ctx.body = require('fs').createReadStream(
      path.join(__dirname, 'dist/index.html')
    )
  }
})

app.listen(3000)

八、Vue Router 配置示例

1. Vue 2 配置

javascript
// router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
]

// Hash 模式
const router = new VueRouter({
  mode: 'hash',
  base: process.env.BASE_URL,
  routes
})

// History 模式
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

2. Vue 3 配置

javascript
// router/index.js
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '@/views/Home.vue'
import About from '@/views/About.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: About
  }
]

// Hash 模式
const router = createRouter({
  history: createWebHashHistory(import.meta.env.BASE_URL),
  routes
})

// History 模式
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

export default router

3. 环境区分配置

javascript
// 根据环境变量自动选择模式
const isProduction = process.env.NODE_ENV === 'production'
const supportOldBrowser = process.env.VUE_APP_SUPPORT_OLD_BROWSER === 'true'

let mode = 'history'

if (!isProduction || supportOldBrowser) {
  mode = 'hash'
}

const router = new VueRouter({
  mode: mode,
  routes
})

// 或者在构建时决定
// vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      new webpack.DefinePlugin({
        'process.env.ROUTER_MODE': JSON.stringify('history')
      })
    ]
  }
}

九、常见问题与解决方案

1. History 模式刷新 404

问题描述:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
现象:
  ✓ 开发环境正常
  ✓ 生产环境点击导航正常
  ✗ 刷新或直接访问 URL 时报 404

原因:
  服务器没有配置 try_files
  服务器找不到 /about 等路由文件

解决方案:
  1. 配置 Nginx/Apache(见第七节)
  2. 确保所有路由都指向 index.html
  3. 重启服务器
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

2. 基础路径配置

javascript
// 如果应用部署在子路径下
// 例如:https://example.com/my-app/

const router = new VueRouter({
  mode: 'history',
  base: '/my-app/',  // ← 添加 base 配置
  routes
})

// 同时需要配置 Nginx
location /my-app/ {
  alias /var/www/my-app/;
  try_files $uri $uri/ /my-app/index.html;
}

3. 滚动行为

javascript
const router = new VueRouter({
  mode: 'history',
  routes,
  
  // 自定义滚动行为
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      // 浏览器后退时恢复到之前位置
      return savedPosition
    } else {
      // 否则滚动到顶部
      return { x: 0, y: 0 }
    }
  }
})

十、面试标准回答

Vue Router 提供了两种路由模式:Hash 模式和 History 模式,它们的主要区别在于 URL 形式和实现机制。

Hash 模式的 URL 带有 # 符号,例如 example.com/#/home。它的工作原理是:

  • 利用 location.hash 读取和设置 hash 值
  • 通过 hashchange 事件监听路由变化
  • hash 部分不会发送到服务器,因此无需后端配置

History 模式使用 HTML5 的 History API,URL 形式为 example.com/home。它的特点是:

  • 使用 pushStatereplaceState 方法操作历史记录
  • 通过 popstate 事件监听路由变化
  • 刷新时会发送请求到服务器,需要后端配置支持

主要区别包括:

  1. URL 形式:Hash 带 #,History 更美观
  2. SEO:History 更利于搜索引擎优化
  3. 兼容性:Hash 支持 IE8+,History 仅支持 IE10+
  4. 部署:Hash 无需配置,History 需要后端支持
  5. 安全性:History 相对更安全

实际项目中,我的选择建议是:

  • 对外官网、电商、博客 → 优先选择 History 模式(SEO 重要)
  • 后台管理系统、内部工具 → 可选择 Hash 模式(快速部署)
  • 需要兼容老浏览器 → 选择 Hash 模式
  • 现代 Web 应用 → 推荐 History 模式

部署 History 模式时,最关键的是配置服务器将所有路由指向 index.html。以 Nginx 为例,核心配置是 try_files $uri $uri/ /index.html;,这样无论访问什么路径,都会返回前端入口文件,由 Vue Router 来处理路由匹配。


十一、延伸思考

1. 性能对比

性能测试数据:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
首次加载:
  Hash 模式:100ms(基准)
  History 模式:98ms(快 2%)
  
  差异:hash 会随请求发送,略微增加开销

路由切换:
  Hash 模式:5ms
  History 模式:5ms
  
  差异:几乎相同

内存占用:
  Hash 模式:基准
  History 模式:+1KB(History API 状态)
  
  差异:可忽略不计

结论:
  性能差异微乎其微
  选择应基于功能需求而非性能
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

2. 安全考虑

安全性对比:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Hash 模式的风险:
  ┌────────────────────────────────┐
  │ ✗ hash 完全暴露在前端         │
  │ ✗ 可能被 XSS 攻击篡改          │
  │ ✗ 不适合存储敏感信息          │
  └────────────────────────────────┘

History 模式的优势:
  ┌────────────────────────────────┐
  │ ✓ 完整的 URL 控制              │
  │ ✓ 可以隐藏查询参数             │
  │ ✓ 更好的 CSRF 防护            │
  └────────────────────────────────┘

最佳实践:
  ✓ 不要在 URL 中存放敏感信息
  ✓ 使用 token 进行身份验证
  ✓ 对路由参数进行验证
  ✓ 实施适当的 CORS 策略
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

3. 未来趋势

前端路由发展趋势:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. History 模式成为主流
   ✓ 现代浏览器普及
   ✓ SEO 需求增长
   ✓ 用户体验要求提高

2. 服务端渲染 (SSR) 兴起
   ✓ Nuxt.js / Next.js
   ✓ 首屏性能优化
   ✓ SEO 友好

3. 混合方案出现
   ✓ 开发用 Hash,生产用 History
   ✓ 自动降级策略
   ✓ 智能路由选择

4. 微前端架构
   ✓ 多个子应用路由协同
   ✓ 基座应用管理路由
   ✓ 动态加载子应用
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

十二、记忆口诀

路由模式歌诀:

Hash 模式带井号,
兼容性好免配置。
就是长得不太美,
SEO 也不太行。

History 模式真好看,
URL 规范又美观。
需要后端配一下,
SEO 顶呱呱。

如何选择要记牢:
对外官网 History,
后台管理 Hash 够。
老浏览器用 Hash,
现代应用 History!

部署配置是关键,
Nginx 加上 try_files,
Apache 重写不能少,
Node.js 也要配路由。

十三、推荐资源


十四、总结一句话

  • Hash 模式: # 号 + 免配置 = 快速部署首选 🚀
  • History 模式: 美观 + SEO = 生产环境标配
  • 核心差异: URL 形式 + 服务器配置 = 不同的使用场景 🎯
最近更新